package com.ld.annotation;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.util.Collections;

@Aspect
@Component
public class RedisCacheAspect {
    private Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    private static final String LD_USER_CACHE="LD:USER:CACHE";

    @Pointcut(value = "@annotation(com.ld.annotation.RedisCache)")
    public void pointcut(){}

    @Around("pointcut()")
    public Object handle(ProceedingJoinPoint point) throws Throwable {

        Method currentMethod = getCurrendMethod(point);



        RedisCache cache = currentMethod.getAnnotation(RedisCache.class);
        String key = "";
        if(StringUtils.isBlank(cache.key())){
            key = currentMethod.getName();
        }else{
            key = cache.key();
        }
        Object[] os = point.getArgs();
        if(os!=null && os.length>0){
            key += JSON.toJSONString(os);
        }
        key = getKey(point,key);
        if(cache.flush()){
            redisTemplate.delete(key);
        }
        Boolean hasKey = redisTemplate.opsForHash().hasKey(LD_USER_CACHE,key);
        if(hasKey){
            logger.info("{}从缓存中获取数据",key);
            Object o = redisTemplate.opsForHash().get(LD_USER_CACHE,key);
            if(!ObjectUtils.isEmpty(o)){
                logger.info("缓存中的数据："+JSON.toJSONString(o));
                return o;
            }
        }
        Object result = point.proceed(); //获取方法执行结果。
        if(!ObjectUtils.isEmpty(result)){
            redisTemplate.opsForHash().put(LD_USER_CACHE,key,result);
            redisTemplate.expire(LD_USER_CACHE,cache.expire(),cache.unit());
        }
        logger.info("{}从数据库中获取数据.",key);
        logger.info("数据库中的数据:"+JSON.toJSONString(result));
        return result;
    }

    private Method getCurrendMethod(ProceedingJoinPoint point) throws NoSuchMethodException {
        Signature sig = point.getSignature();
        MethodSignature msig = (MethodSignature) sig;
        Object target = point.getTarget();
        return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
    }
    private String getKey(ProceedingJoinPoint point,String extra) throws NoSuchMethodException {
        Method currentMethod = getCurrendMethod(point);
        String methodName = currentMethod.getName();
        StringBuilder key = new StringBuilder();
        /*key.append(LD_USER_CACHE);
        key.append(":");*/
        key.append(methodName);
//        key.append();
        key.append(null == extra ? "" : "_"+extra);
        logger.info("redis key:"+key.toString());
        return key.toString();
    }
}
